package com.uniview.filter;

import com.uniview.config.GatewayConstants;
import com.uniview.constants.CommonConstants;
import com.uniview.utils.EncryptUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author lux
 * @date: 2020/1/7
 * @desc: 添加网关自定义请求头RequestId
 * requestId需要每次都不一样，相当于有一条requestId穿插在整个交易链中
 * 外部只能从网关这边请求微服务，经过网关时设置requestHeader，然后将此值存放在redis里面，在其他微服务之间传递
 * 微服务怎么鉴定请求是从网关过来的，并且不是伪造，微服务
 */
@Slf4j
public class PreRequestFilter implements GlobalFilter,Ordered {
    // 过期时间
    private final static long expiration = 1000 * 60 * 5;
    // 过期前1分钟
    private final static long lastTime = 1000 * 60;
    @Autowired
    RedisTemplate redisTemplate;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //添加自定义请求头
        String rid = create(CommonConstants.X_REQUEST_ID);
        ServerHttpRequest request = exchange.getRequest().mutate().header(CommonConstants.X_REQUEST_ID,rid).build();
        ServerHttpResponse response = exchange.getResponse();
        //将现在的request 变成 change对象
        ServerWebExchange build = exchange.mutate().request(request).response(response).build();
        // 添加请求时间
        build.getAttributes().put("requestTime", new Date());
        return chain.filter(build);
    }

    @Override
    public int getOrder() {
        return GatewayConstants.PRE_REQUEST;
    }

    public String create(String key){
        if(StringUtils.isBlank(key)){
            return null;
        }
        String secretKey;
        if(redisTemplate.hasKey(key)){
            if(redisTemplate.boundHashOps(key).getExpire() < lastTime){
                redisTemplate.opsForValue().set(key, EncryptUtils.md5Hex(UUID.randomUUID().toString()),expiration,TimeUnit.SECONDS);
            }
            secretKey = (String) redisTemplate.opsForValue().get(key);
        }else{
            secretKey = EncryptUtils.md5Hex(UUID.randomUUID().toString());
            redisTemplate.opsForValue().set(key,secretKey,expiration,TimeUnit.SECONDS);
        }
        return secretKey;
    }
}
